package edu.cicese.tm;

import com.jgoodies.looks.plastic.PlasticXPLookAndFeel;
import com.sun.awt.AWTUtilities;

import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.TargetDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.awt.geom.Line2D;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.util.Vector;

/**
 * Created by: Eduardo Quintana Contreras
 * Date: 16/03/11
 * Time: 04:15 PM
 */
public class DialogAudio extends JDialog {
	private FrameTagCreation frmTagCreation;
	private FrameTagEdition frmTagEdition;
	private Playback playback = new Playback();
	private Capture capture = new Capture();
	private AudioFormat audioFormat;
	private AudioInputStream audioInputStream;
	private SamplingGraph samplingGraph;

	// Audio format
	private float sampleRate = 22050; //8000, *11025, 16000, *22050, 44100
	private float frameRate = 22050f; //8000, 11025, 16000, *22050, 44100
	private int sampleSize = 16; //8 *16
	private int channels = 2; //*1 *2

	private JButton btnPlay, btnRecord, btnStop, btnAccept, btnCancel;
	private JLabel lblInfo;

	private String errStr;
	private Vector lines = new Vector();
	private double duration, seconds;
	private boolean error = false, playing = false, recording = false, recorded = false;
	public static boolean tmpAudioSaved = false;
	private File file;

	public DialogAudio(FrameTagCreation owner) {
		super(owner);
		frmTagCreation = owner;
		AWTUtilities.setWindowOpacity(frmTagCreation, 0.75f);
		initComponents();
	}

//	public DialogAudio(FrameTagCreation owner, File audioFile) {
//		super(owner);
//		frmTagCreation = owner;
//		AWTUtilities.setWindowOpacity(frmTagCreation, 0.75f);
//		initComponents();
//		createAudioInputStream(audioFile, true);
//	}

	public DialogAudio(FrameTagEdition owner, File audioFile) {
		super(owner);
		frmTagEdition = owner;
		AWTUtilities.setWindowOpacity(frmTagEdition, 0.75f);
		initComponents();
		createAudioInputStream(audioFile, true);
//		if (audioFile.exists()) {
//			createAudioInputStream(audioFile, true);
//		}
	}

	//! Creates GUI components
	private void initComponents() {
		audioFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, sampleRate, sampleSize, channels,
				(sampleSize / 8) * channels, frameRate, false);

		setLayout(null);
		setTitle("Clip de audio");
		setSize(316, 142);
		setIconImage(new ImageIcon(getClass().getClassLoader().getResource("icons/icon.png")).getImage());
		setResizable(false);
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				closeWindow(false);
			}
		});

		samplingGraph = new SamplingGraph();
		samplingGraph.setBounds(1, 1, 298, 48);

		JPanel pWave = new JPanel();
		pWave.setBounds(5, 5, 300, 50);
		pWave.setBorder(new LineBorder(Color.LIGHT_GRAY, 1));
		pWave.setLayout(null);
		pWave.add(samplingGraph);
		getContentPane().add(pWave);

		lblInfo = new JLabel();
		SwingUtil.addLabel(lblInfo, 5, 60, 300, 15, "", null, getContentPane());
		lblInfo.setFont(new Font("Segoe UI", Font.PLAIN, 14));

		btnPlay = new JButton();
		addButton(btnPlay, 5, 78, 32, 32, "Reproducir", "play", null, getContentPane());
		btnPlay.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				actionPlay();
			}
		});

		btnRecord = new JButton();
		addButton(btnRecord, 42, 78, 32, 32, "Grabar", "record", null, getContentPane());
		btnRecord.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				actionRecord();
			}
		});

		btnStop = new JButton();
		addButton(btnStop, 42, 78, 32, 32, "Detener", "stop", null, getContentPane());
		btnStop.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				actionStop();
			}
		});
		btnStop.setVisible(false);

		btnAccept = new JButton();
		addButton(btnAccept, 236, 78, 32, 32, "Aceptar", "accept", null, getContentPane());
		btnAccept.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				actionAccept();
			}
		});

		btnCancel = new JButton();
		addButton(btnCancel, 273, 78, 32, 32, "Cancelar", "cancel", null, getContentPane());
		btnCancel.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				actionCancel();
			}
		});

		Rectangle window = getBounds();
		Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
		setLocation((screen.width - window.width) / 2, (screen.height - window.height) / 2);
		setVisible(true);
	}

	//! Closes the dialog and brings back the owner window
	private void closeWindow(boolean acceptOrCancel) {
		closeResources();
		if (acceptOrCancel) {
			setVisible(false);
			dispose();
		}
		if (frmTagCreation != null) {
//			frmTagCreation.audioClip = recorded;
			frmTagCreation.setEnabled(true);
			frmTagCreation.toFront();
			AWTUtilities.setWindowOpacity(frmTagCreation, 1f);
		}
		else {
//			frmTagEdition.newAudioClip = recorded;
			frmTagEdition.setEnabled(true);
			frmTagEdition.toFront();
			AWTUtilities.setWindowOpacity(frmTagEdition, 1f);
		}
	}

	//! Called when the button Accept is clicked. Saves the recorded audio to a temporal file
	private void actionAccept() {
		if (recorded) {
			if (frmTagCreation != null) {
				frmTagCreation.chbAudio.setSelected(true);
			}
			else {
				frmTagEdition.chbAudio.setSelected(true);
			}
			saveToFile();
			tmpAudioSaved = true;
		}
		closeWindow(true);
	}

	//! Called when the button Cancel is clicked
	private void actionCancel() {
		closeWindow(true);
	}

	//! Called when the button Play is clicked. Plays the audio clip loaded or recorded
	private void actionPlay() {
		if (!playing) {
			playing = true;
			if (playback.thread != null) {
				playback.line.start();
			}
			else {
				playback.start();
				samplingGraph.start();
				btnRecord.setVisible(false);
				btnStop.setVisible(true);
			}
			changeButton(btnPlay, "Pausar", "pause");
		}
		else {
			playing = false;
			if (playback.thread != null) {
				playback.line.stop();
			}
			changeButton(btnPlay, "Reproducir", "play");
		}
	}

	//! Called when the button Stop is clicked. Stops the audio clip reproduction
	private void actionStop() {
		playing = false;
		playback.stop();
		samplingGraph.stop();
		btnRecord.setVisible(true);
		btnStop.setVisible(false);
		changeButton(btnPlay, "Reproducir", "play");
	}

	//! Called when the button Record is clicked. Records an audio clip
	private void actionRecord() {
		recorded = false;
		if (!recording) {
			recording = true;
			file = null;
			capture.start();
			samplingGraph.start();
			btnPlay.setVisible(false);
			btnAccept.setVisible(false);
			changeButton(btnRecord, "Detener grabación", "stopRecording");
		}
		else {
			recorded = true;
			recording = false;
			lines.removeAllElements();
			capture.stop();
			samplingGraph.stop();
			btnPlay.setVisible(true);
			btnAccept.setVisible(true);
			changeButton(btnRecord, "Grabar", "record");
		}
	}

	//! Saves the audio clip to a temporal file
	public void saveToFile() {
//        if (audioInputStream == null) {
//            reportStatus("No loaded audio to save");
//            return;
//        } else if (file != null) {
//            createAudioInputStream(file, false);
//        }

        // Reset to the beginning of the captured data
		try {
			audioInputStream.reset();
		} catch (IOException e) {
			reportStatus("Unable to reset stream " + e);
			return;
		}

		// Write the audio file
        File audioFile = new File(Utilities.spaceDir + "tmpAudio.wav");
		try {
			AudioSystem.write(audioInputStream, AudioFileFormat.Type.WAVE, audioFile);
		} catch (IOException e) {
			reportStatus(e.toString());
		}

        samplingGraph.repaint();
    }

	/*
createAudioInputStream(fc.getSelectedFile(), true);
    }*/

    public void createAudioInputStream(File file, boolean updateComponents) {
        if (file != null && file.isFile()) {
            try {
                this.file = file;
                errStr = null;
                audioInputStream = AudioSystem.getAudioInputStream(file);
                btnPlay.setEnabled(true);
//	            System.out.println("CreateAudioInputStream " + audioInputStream.getFrameLength() + " frameLength, " +
//	                    audioInputStream.getFormat().getFrameRate() + " frameRate");
                long milliseconds = (long)((audioInputStream.getFrameLength() * 1000) / audioInputStream.getFormat().getFrameRate());
                duration = milliseconds / 1000.0;
                if (updateComponents) {
                    samplingGraph.createWaveform(null);
                }
            } catch (UnsupportedAudioFileException e) {
                reportStatus(e.toString());
            } catch (IOException e) {
                reportStatus(e.toString());
            }
        } else {
            reportStatus("Audio file required.");
        }
    }

	private void reportStatus(String msg) {
        if ((errStr = msg) != null) {
            System.out.println(errStr);
            samplingGraph.repaint();
        }
    }

	//! Changes a button visible state, tooltip text and icon images
	private void changeButton(JButton button, String toolTipText, String iconName) {
		button.setToolTipText(toolTipText);
		button.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/" + iconName + ".png")));
		button.setRolloverIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/" + iconName + "O.png")));
		button.setPressedIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/" + iconName + "P.png")));
	}

	//! Adds a JButton
	private void addButton(JButton button, int x, int y, int width, int height,
	                              String toolTipText, String iconName, JPanel pane, Container container) {
		Icon icon = new ImageIcon(getClass().getClassLoader().getResource("icons/" + iconName + ".png"));
		Icon rIcon = new ImageIcon(getClass().getClassLoader().getResource("icons/" + iconName + "O.png"));
		Icon pIcon = new ImageIcon(getClass().getClassLoader().getResource("icons/" + iconName + "P.png"));
		SwingUtil.addButton(button, x, y, width, height, toolTipText, icon, rIcon, pIcon, pane, container);
	}

	//!
	private void closeResources() {
		if (recording) {
			lines.removeAllElements();
			capture.stop();
			samplingGraph.stop();
		}
	}

	//! Gets the time in minutes and seconds
	private String getMinutes(double seconds) {
		int min = (int) (Math.floor(seconds / 60));
		int sec = (int) (Math.floor(seconds) % 60);
		return Utilities.addZeros(min, 2) + ":" + Utilities.addZeros(sec, 2);
	}

	class Playback implements Runnable {
        SourceDataLine line;
        Thread thread;

        public void start() {
            errStr = null;
            thread = new Thread(this);
//            thread.setName("Playback");
            thread.start();
        }

        public void stop() {
            thread = null;
        }

        private void shutDown(String message) {
            if ((errStr = message) != null) {
                System.err.println(errStr);
                samplingGraph.repaint();
            }
            if (thread != null) {
                thread = null;
                samplingGraph.stop();
	            btnRecord.setVisible(true);
				btnStop.setVisible(false);
				changeButton(btnPlay, "Reproducir", "play");
	            playing = false;
            }
        }

        public void run() {
            // Reload the file if loaded by file
            if (file != null) {
                createAudioInputStream(file, false);
            }

            // Make sure there is something to play
            if (audioInputStream == null) {
	            //TODO: Display error msg
                shutDown("No loaded audio to play back");
                return;
            }
            // Reset to the beginning of the stream
	        try {
		        audioInputStream.reset();
	        } catch (IOException e) {
		        System.out.println("Unable to reset the stream\n" + e);
//		        shutDown("Unable to reset the stream\n" + e);
//                return;
	        }

            AudioInputStream playbackInputStream = AudioSystem.getAudioInputStream(audioFormat, audioInputStream);

            if (playbackInputStream == null) {
                shutDown("Unable to convert stream of format " + audioInputStream + " to format " + audioFormat);
                return;
            }

            // Make sure a compatible line is supported.
            DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
            if (!AudioSystem.isLineSupported(info)) {
                shutDown("Line matching " + info + " not supported.");
                return;
            }

            // Get and open the source data line for playback.
            try {
                line = (SourceDataLine) AudioSystem.getLine(info);
	            int bufSize = 16384;
	            line.open(audioFormat, bufSize);
            } catch (LineUnavailableException ex) {
                shutDown("Unable to open the line: " + ex);
                return;
            }

            // Play back the captured audio data
//	        System.out.println(audioFormat.getFrameSize() + " frameSize, debería ser: " + (sampleSize / 8) * channels);
            int frameSizeInBytes = audioFormat.getFrameSize();
            int bufferLengthInFrames = line.getBufferSize() / 8;
            int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
            byte[] data = new byte[bufferLengthInBytes];
            int numBytesRead;

            // Start the source data line
            line.start();
            while (thread != null) {
	            try {
		            if ((numBytesRead = playbackInputStream.read(data)) == -1) {
						break;
					}
		            int numBytesRemaining = numBytesRead;
					while (numBytesRemaining > 0 ) {
						numBytesRemaining -= line.write(data, 0, numBytesRemaining);
					}
	            } catch (IOException e) {
		            shutDown("Error during playback: " + e);
                    break;
	            }
            }

            // We reached the end of the stream. Let the data play out, then stop and close the line.
            if (thread != null) {
                line.drain();
            }
            line.stop();
//            line.close();
            line = null;
            shutDown(null);
        }
    }

	class Capture implements Runnable {
        TargetDataLine line;
        Thread thread;

        public void start() {
            thread = new Thread(this);
            thread.start();
        }

        public void stop() {
            thread = null;
        }

		private void shutDown(String message) {
			if ((errStr = message) != null && thread != null) {
				thread = null;
				samplingGraph.stop();
				changeButton(btnRecord, "Grabar", "record");
				btnPlay.setVisible(true);
				System.err.println(errStr);
				samplingGraph.repaint();
			}
        }

        public void run() {
            duration = 0;
            audioInputStream = null;
	        error = false;

            DataLine.Info info = new DataLine.Info(TargetDataLine.class, audioFormat);

	        // Make sure a compatible line is supported.
            if (!AudioSystem.isLineSupported(info)) {
	            shutDown("Line matching " + info + " not supported.");
                return;
            }

            // Get and open the target data line for capture.
	        try {
		        line = (TargetDataLine) AudioSystem.getLine(info);
		        line.open(audioFormat, line.getBufferSize());
	        } catch (LineUnavailableException e) {
		        shutDown("Unable to open the line: " + e);
	        }

            // Play back the captured audio data
            ByteArrayOutputStream out = new ByteArrayOutputStream();
//	        System.out.println(audioFormat.getFrameSize() + " frameSize, debería ser: " + (sampleSize / 8) * channels);
            int frameSizeInBytes = audioFormat.getFrameSize();
            int bufferLengthInFrames = line.getBufferSize() / 8;
            int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
            byte[] data = new byte[bufferLengthInBytes];
            int numBytesRead;

            line.start();

            while (thread != null) {
                if((numBytesRead = line.read(data, 0, bufferLengthInBytes)) == -1) {
                    break;
                }
                out.write(data, 0, numBytesRead);
            }

            // We reached the end of the stream, stop and close the line.
            line.stop();
            line.close();
            line = null;

            // Stop and close the output stream
            try {
                out.flush();
                out.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }

            // Load bytes into the audio input stream for playback
            byte audioBytes[] = out.toByteArray();
            ByteArrayInputStream bais = new ByteArrayInputStream(audioBytes);
//	        System.out.println(audioFormat.getFrameSize() + " frameSize, debería ser: " + (sampleSize / 8) * channels);
            audioInputStream = new AudioInputStream(bais, audioFormat, audioBytes.length / frameSizeInBytes);

//	        System.out.println(audioFormat.getFrameRate() + " vs " + frameRate);
            long milliseconds = (long)((audioInputStream.getFrameLength() * 1000) / audioFormat.getFrameRate());
            duration = milliseconds / 1000.0;

	        try {
		        audioInputStream.reset();
	        } catch (IOException e) {
		        e.printStackTrace();
	        }

	        // Create waveform
            samplingGraph.createWaveform(audioBytes);
        }
    }

	class SamplingGraph extends JPanel implements Runnable {
        private Thread thread;
		private Color waveColor = new Color(79, 129, 189);
//		private Font font10 = new Font("Segoe UI", Font.PLAIN, 10);
		private Font font12 = new Font("Segoe UI", Font.PLAIN, 12);

        public SamplingGraph() {
            setBackground(Color.WHITE);
//	        setBorder(new LineBorder(Color.LIGHT_GRAY, 1));
//	        setBorder(new LineBorder(Color.BLACK, 1));
        }

        @SuppressWarnings({"ResultOfMethodCallIgnored", "unchecked"})
        public void createWaveform(byte[] audioBytes) {
            lines.removeAllElements();
            if (audioBytes == null) {
//	            System.out.println(audioFormat.getFrameSize() + " vs FrameSize " + (sampleSize / 8) * channels);
	            audioBytes = new byte[(int) (audioInputStream.getFrameLength() * audioFormat.getFrameSize())];
//	            audioBytes = new byte[(int) (44100.0F * audioFormat.getFrameSize())];
	            try {
		            audioInputStream.read(audioBytes);
	            } catch (IOException e) {
		            e.printStackTrace();
		            samplingGraph.repaint();
	            }
            }

				Dimension d = getSize();
				int w = d.width;
				int h = d.height;
				int[] audioData = null;
//				System.out.println(audioFormat.getSampleSizeInBits() + " sampleSize vs " + sampleSize);
				if (audioFormat.getSampleSizeInBits() == 16) {
					int audioBytesLength = audioBytes.length / 2;
					audioData = new int[audioBytesLength];
//	                System.out.println(audioFormat.isBigEndian() + " vs false");
					if (audioFormat.isBigEndian()) {
						for (int i = 0; i < audioBytesLength; i++) {
							/* First byte is MSB (high order) */
							int MSB = (int) audioBytes[2*i];
							/* Second byte is LSB (low order) */
							int LSB = (int) audioBytes[2*i+1];
							audioData[i] = MSB << 8 | (255 & LSB);
						}
					}
					else {
						for (int i = 0; i < audioBytesLength; i++) {
							/* First byte is LSB (low order) */
							int LSB = (int) audioBytes[2*i];
							/* Second byte is MSB (high order) */
							int MSB = (int) audioBytes[2*i+1];
							audioData[i] = MSB << 8 | (255 & LSB);
						}
					}
				}
				else if (audioFormat.getSampleSizeInBits() == 8) {
					int audioBytesLength = audioBytes.length;
					audioData = new int[audioBytesLength];
//					System.out.println(audioFormat.getEncoding().toString() + " vs PC_SIGNED");
					if (audioFormat.getEncoding().toString().startsWith("PCM_SIGN")) {
						for (int i = 0; i < audioBytes.length; i++) {
							audioData[i] = audioBytes[i];
						}
					} 
					else {
						for (int i = 0; i < audioBytes.length; i++) {
							audioData[i] = audioBytes[i] - 128;
					}
				}
            }

//	        System.out.println(audioFormat.getFrameSize() + " vs FrameSize " + (sampleSize / 8) * channels);
			int frames_per_pixel = audioBytes.length / audioFormat.getFrameSize() / w;
			byte my_byte;
			double y_last = 0;
//	        System.out.println(audioFormat.getChannels() + " vs channels " + channels);
			int numChannels = audioFormat.getChannels();
			for (double x = 0; x < w && audioData != null; x++) {
				int idx = (int) (frames_per_pixel * numChannels * x);
				if (audioFormat.getSampleSizeInBits() == 8) {
					my_byte = (byte) audioData[idx];
				}
				else {
					my_byte = (byte) (128 * audioData[idx] / 32768 );
				}
				double y_new = (double) (h * (128 - my_byte) / 256);
				lines.add(new Line2D.Double(x, y_last, x, y_new));
				y_last = y_new;
			}

			repaint();


//            Dimension d = getSize();
//            int w = d.width;
//            int h = d.height;
//
//	        int audioBytesLength = audioBytes.length;
//			int[] audioData = new int[audioBytesLength];
//	        for (int i = 0; i < audioBytesLength; i++) {
//				audioData[i] = audioBytes[i];
//			}
//
//
//	        int framesPerPixel = audioBytesLength / audioFormat.getFrameSize() / w;
////            int framesPerPixel = 1;
//            byte myByte;
//            double yLast = 0;
//            int numChannels = audioFormat.getChannels();
//	        System.out.println(numChannels + " canales.");
////	        int numChannels = 1;
//            for (double x = 0; x < w; x++) {
//                int idx = (int) (framesPerPixel * numChannels * x);
//	            myByte = (byte) audioData[idx];
//                double yNew = (double) (h * (128 - myByte) / 256);
//                lines.add(new Line2D.Double(x, yLast, x, yNew));
//                yLast = yNew;
//            }
//
//            repaint();
        }

        public void paint(Graphics g) {
            Dimension d = getSize();
            int w = d.width;
            int h = d.height;

            Graphics2D g2 = (Graphics2D) g;
//            g2.setBackground(getBackground());
            g2.clearRect(0, 0, w, h);

            if (error) {
                g2.setColor(waveColor);
                g2.setFont(new Font("Segoe UI", Font.BOLD, 18));
                g2.drawString("ERROR", 5, 20);
                AttributedString as = new AttributedString(errStr);
                as.addAttribute(TextAttribute.FONT, font12, 0, errStr.length());
                AttributedCharacterIterator aci = as.getIterator();
                FontRenderContext frc = g2.getFontRenderContext();
                LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);
                float x = 5, y = 25;
                lbm.setPosition(0);
                while (lbm.getPosition() < errStr.length()) {
                    TextLayout tl = lbm.nextLayout(w-x-5);
                    if (!tl.isLeftToRight()) {
                        x = w - tl.getAdvance();
                    }
                    tl.draw(g2, x, y += tl.getAscent());
                    y += tl.getDescent() + tl.getLeading();
                }
            } else if (capture.thread != null) {
//	            lblInfo.setText(String.valueOf(seconds));
	            lblInfo.setText(getMinutes(seconds));
            } else {
                if (audioInputStream != null) {
//	                lblInfo.setText(seconds + "/" + duration);
	                lblInfo.setText(getMinutes(seconds) + "/" + getMinutes(duration));

                    // Render sampling graph
                    g2.setColor(waveColor);
                    for (int i = 1; i < lines.size(); i++) {
                        g2.draw((Line2D) lines.get(i));
                    }

                    // Draw current position
                    if (seconds != 0) {
                        double loc = seconds / duration * w;
	                    g2.setColor(new Color(255, 0, 0, 100));
//                        g2.setColor(Color.RED);
                        g2.setStroke(new BasicStroke(2));
                        g2.draw(new Line2D.Double(loc, 2, loc, h - 2));
                    }
                }
            }
        }

        public void start() {
            thread = new Thread(this);
            thread.start();
            seconds = 0;
        }

        public void stop() {
            if (thread != null) {
                thread.interrupt();
            }
            thread = null;
        }

        @SuppressWarnings({"AccessStaticViaInstance"})
        public void run() {
            seconds = 0;
            while (thread != null) {
                if ((playback.line != null) && (playback.line.isOpen()) ) {
                    long milliseconds = playback.line.getMicrosecondPosition() / 1000;
                    seconds =  milliseconds / 1000.0;
                }
                else if ((capture.line != null) && (capture.line.isActive())) {
                    long milliseconds = capture.line.getMicrosecondPosition() / 1000;
                    seconds =  milliseconds / 1000.0;
                }

	            try {
		            thread.sleep(25);
	            } catch (InterruptedException e) {
//		            e.printStackTrace();
		            break;
	            }

                repaint();

                while ((capture.line != null && !capture.line.isActive()) ||
                       (playback.line != null && !playback.line.isOpen()))
                {
	                try {
		                thread.sleep(10);
	                } catch (InterruptedException e) {
//		                e.printStackTrace();
		                break;
	                }
                }
            }
            seconds = 0;
            repaint();
        }
    }


	public static void main(String[] a) {
		try {
			UIManager.setLookAndFeel(new PlasticXPLookAndFeel());
			UIManager.put("Panel.background", Color.WHITE);
		} catch (UnsupportedLookAndFeelException e) {
			e.printStackTrace();
		}
		new DialogAudio(null);
	}
}
